home *** CD-ROM | disk | FTP | other *** search
- Subject: v24i093: Program identifier database tools, Part05/07
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: d7239bcc 65a3e35c b7e56c4a 04c06e6c
-
- Submitted-by: Tom Horsley <tom@hcx2.ssd.csd.harris.com>
- Posting-number: Volume 24, Issue 93
- Archive-name: mkid2/part05
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 5 (of 7)."
- # Contents: iidfun.c mkid.c
- # Wrapped by tom@hcx2 on Tue Feb 26 10:03:05 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'iidfun.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'iidfun.c'\"
- else
- echo shar: Extracting \"'iidfun.c'\" \(17113 characters\)
- sed "s/^X//" >'iidfun.c' <<'END_OF_FILE'
- X/* iidfun.c - This file holds the utility functions called from iid.y
- X */
- X
- X#include "iiddef.h"
- X#ifdef USE_ALLOCA
- X
- X/* Apparently Sun's need the following to work correctly */
- X#ifdef sun
- X#include <alloca.h>
- X#endif /* sun */
- X
- X/* Define TEMP_ALLOC to call alloca, and TEMP_FREE to do nothing */
- X
- X#define TEMP_ALLOC(s) alloca(s)
- X#define TEMP_FREE(s)
- X
- X#else
- X
- X/* Not using alloca() (not everyone has it) - define TEMP_ALLOC to call
- X * malloc() and TEMP_FREE to call free().
- X */
- X#define TEMP_ALLOC(s) malloc(s)
- X#define TEMP_FREE(s) free(s)
- X
- X#endif /* USE_ALLOCA */
- X
- X/* ArgListSize - count the size of an arg list so can alloca() enough
- X * space for the command.
- X */
- Xint
- XArgListSize(idlp)
- X id_list_type * idlp ;
- X{
- X id_type * idep ;
- X int size = 0;
- X
- X idep = idlp->id_list ;
- X while (idep != NULL) {
- X size += 1 + strlen(idep->id);
- X idep = idep->next_id;
- X }
- X return size;
- X}
- X
- X/* SetListSize - count the size of a string build up from a set so we can
- X * alloca() enough space for args.
- X */
- Xint
- XSetListSize(sp)
- X set_type * sp ;
- X{
- X int i ;
- X int size = 0 ;
- X
- X for (i = 0; i < NextFileNum; ++i) {
- X if (FileList[i]->mask_word < sp->set_size) {
- X if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
- X size += 1 + strlen(FileList[i]->name);
- X }
- X }
- X }
- X return size;
- X}
- X
- X/* FlushFiles - clear out the TheFiles array for the start of a new
- X * query.
- X */
- Xvoid
- XFlushFiles()
- X{
- X int i ;
- X
- X if (TheFiles != NULL) {
- X for (i = 0; i <= MaxCurFile; ++i) {
- X TheFiles[i] = 0 ;
- X }
- X }
- X MaxCurFile = 0 ;
- X}
- X
- X/* fatal - sometimes the only thing to do is die...
- X */
- Xvoid
- Xfatal(s)
- X{
- X fprintf(stderr,"Fatal error: %s\n",s) ;
- X exit(1) ;
- X}
- X
- X/* CountBits - count the number of bits in a bit set. Actually fairly
- X * tricky since it needs to deal with sets having infinite tails
- X * as a result of a NOT operation.
- X */
- Xint
- XCountBits(sp)
- X set_type * sp ;
- X{
- X unsigned long bit_mask ;
- X int count = 0 ;
- X int i ;
- X
- X i = 0;
- X for ( ; ; ) {
- X for (bit_mask = high_bit; bit_mask != 0; bit_mask >>= 1) {
- X if (bit_mask == NextMaskBit && i == NextMaskWord) {
- X return(count) ;
- X }
- X if (i < sp->set_size) {
- X if (sp->set_data[i] & bit_mask) {
- X ++count ;
- X }
- X } else {
- X if (sp->set_tail == 0) return count;
- X if (sp->set_tail & bit_mask) {
- X ++count;
- X }
- X }
- X }
- X ++i;
- X }
- X}
- X
- X/* OneDescription - Print a description of a set. This includes
- X * the set number, the number of files in the set, and the
- X * set description string.
- X */
- Xvoid
- XOneDescription(sp)
- X set_type * sp ;
- X{
- X int elt_count ;
- X char setnum[20] ;
- X
- X sprintf(setnum,"S%d",sp->set_num) ;
- X elt_count = CountBits(sp) ;
- X printf("%5s %6d %s\n",setnum,elt_count,sp->set_desc) ;
- X}
- X
- X/* DescribeSets - Print description of all the sets.
- X */
- Xvoid
- XDescribeSets()
- X{
- X int i ;
- X
- X if (NextSetNum > 0) {
- X for (i = 0; i < NextSetNum; ++i) {
- X OneDescription(TheSets[i]) ;
- X }
- X } else {
- X printf("No sets defined yet.\n") ;
- X }
- X}
- X
- X/* SetList - Go through the bit set and add the file names in
- X * it to an identifier list.
- X */
- Xid_list_type *
- XSetList(idlp, sp)
- X id_list_type * idlp ;
- X set_type * sp ;
- X{
- X int i ;
- X id_type * idep ;
- X
- X for (i = 0; i < NextFileNum; ++i) {
- X if (FileList[i]->mask_word < sp->set_size) {
- X if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
- X idep = (id_type *)malloc(sizeof(id_type) +
- X strlen(FileList[i]->name)) ;
- X if (idep == NULL) {
- X fatal("Out of memory in SetList") ;
- X }
- X idep->next_id = NULL ;
- X strcpy(idep->id, FileList[i]->name) ;
- X idlp = ExtendList(idlp, idep) ;
- X }
- X }
- X }
- X return(idlp) ;
- X}
- X
- X/* PrintSet - Go through the bit set and print the file names
- X * corresponding to all the set bits.
- X */
- Xvoid
- XPrintSet(sp)
- X set_type * sp ;
- X{
- X int i ;
- X
- X for (i = 0; i < NextFileNum; ++i) {
- X if (FileList[i]->mask_word < sp->set_size) {
- X if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
- X printf("%s\n",FileList[i]->name) ;
- X }
- X }
- X }
- X}
- X
- X/* Free up all space used by current set of sets and reset all
- X * set numbers.
- X */
- Xvoid
- XFlushSets()
- X{
- X int i ;
- X
- X for (i = 0; i < NextSetNum; ++i) {
- X free(TheSets[i]->set_desc) ;
- X free(TheSets[i]) ;
- X }
- X NextSetNum = 0 ;
- X}
- X
- X/* InitList - create an empty identifier list.
- X */
- Xid_list_type *
- XInitList()
- X{
- X id_list_type * idlp ;
- X
- X idlp = (id_list_type *)malloc(sizeof(id_list_type)) ;
- X if (idlp == NULL) {
- X fatal("Out of memory in InitList") ;
- X }
- X idlp->id_count = 0 ;
- X idlp->end_ptr_ptr = & (idlp->id_list) ;
- X idlp->id_list = NULL ;
- X return(idlp) ;
- X}
- X
- X/* ExtendList - add one identifier to an ID list.
- X */
- Xid_list_type *
- XExtendList(idlp, idp)
- X id_list_type * idlp ;
- X id_type * idp ;
- X{
- X *(idlp->end_ptr_ptr) = idp ;
- X idlp->end_ptr_ptr = &(idp->next_id) ;
- X return(idlp) ;
- X}
- X
- X/* InitIid - do all initial processing for iid.
- X * 1) Determine the size of a unsigned long for bit set stuff.
- X * 2) Find out the name of the pager program to use.
- X * 3) Create the HelpSet (pointing to the help file).
- X * 4) Setup the prompt.
- X */
- Xvoid
- XInitIid()
- X{
- X unsigned long bit_mask = 1 ; /* find number of bits in long */
- X int i ;
- X char * page ; /* pager program */
- X
- X do {
- X high_bit = bit_mask ;
- X bit_mask <<= 1 ;
- X } while (bit_mask != 0) ;
- X
- X NextMaskBit = high_bit ;
- X
- X page = getenv("PAGER") ;
- X if (page == NULL) {
- X page = PAGER ;
- X }
- X strcpy(Pager, page) ;
- X
- X FlushFiles() ;
- X InstallFile(HELPFILE) ;
- X HelpSet = (set_type *)
- X malloc(sizeof(set_type) + sizeof(unsigned long) * MaxCurFile) ;
- X if (HelpSet == NULL) {
- X fatal("No memory for set in InitIid") ;
- X }
- X HelpSet->set_tail = 0 ;
- X HelpSet->set_desc = NULL ;
- X HelpSet->set_size = MaxCurFile + 1 ;
- X for (i = 0; i <= MaxCurFile; ++i) {
- X HelpSet->set_data[i] = TheFiles[i] ;
- X }
- X
- X page = getenv("PS1") ;
- X if (page == NULL) {
- X page = PROMPT ;
- X }
- X strcpy(Prompt, page) ;
- X}
- X
- X/* InstallFile - install a file name in the symtab. Return the
- X * symbol table pointer of the file.
- X */
- Xsymtab_type *
- XInstallFile(fp)
- X char * fp ;
- X{
- X char c ;
- X unsigned long hash_code ;
- X int i ;
- X char * sp ;
- X symtab_type * symp ;
- X
- X hash_code = 0 ;
- X sp = fp ;
- X while ((c = *sp++) != '\0') {
- X hash_code <<= 1 ;
- X hash_code ^= (unsigned long)(c) ;
- X if (hash_code & high_bit) {
- X hash_code &= ~ high_bit ;
- X hash_code ^= 1 ;
- X }
- X }
- X hash_code %= HASH_SIZE ;
- X symp = HashTable[hash_code] ;
- X while (symp != NULL && strcmp(symp->name, fp)) {
- X symp = symp->hash_link ;
- X }
- X if (symp == NULL) {
- X symp = (symtab_type *)malloc(sizeof(symtab_type) + strlen(fp)) ;
- X if (symp == NULL) {
- X fatal("No memory for symbol table entry in InstallFile") ;
- X }
- X strcpy(symp->name, fp) ;
- X symp->hash_link = HashTable[hash_code] ;
- X HashTable[hash_code] = symp ;
- X if (NextMaskWord >= FileSpace) {
- X FileSpace += 1000 ;
- X if (TheFiles != NULL) {
- X TheFiles = (unsigned long *)
- X realloc(TheFiles, sizeof(unsigned long) * FileSpace) ;
- X } else {
- X TheFiles = (unsigned long *)
- X malloc(sizeof(unsigned long) * FileSpace) ;
- X }
- X if (TheFiles == NULL) {
- X fatal("No memory for TheFiles in InstallFile") ;
- X }
- X for (i = NextMaskWord; i < FileSpace; ++i) {
- X TheFiles[i] = 0 ;
- X }
- X }
- X symp->mask_word = NextMaskWord ;
- X symp->mask_bit = NextMaskBit ;
- X NextMaskBit >>= 1 ;
- X if (NextMaskBit == 0) {
- X NextMaskBit = high_bit ;
- X ++NextMaskWord ;
- X }
- X if (NextFileNum >= ListSpace) {
- X ListSpace += 1000 ;
- X if (FileList == NULL) {
- X FileList = (symtab_type **)
- X malloc(sizeof(symtab_type *) * ListSpace) ;
- X } else {
- X FileList = (symtab_type **)
- X realloc(FileList, ListSpace * sizeof(symtab_type *)) ;
- X }
- X if (FileList == NULL) {
- X fatal("No memory for FileList in InstallFile") ;
- X }
- X }
- X FileList[NextFileNum++] = symp ;
- X /* put code here to sort the file list by name someday */
- X }
- X TheFiles[symp->mask_word] |= symp->mask_bit ;
- X if (symp->mask_word > MaxCurFile) {
- X MaxCurFile = symp->mask_word ;
- X }
- X return(symp) ;
- X}
- X
- X/* RunPager - run the users pager program on the list of files
- X * in the set.
- X */
- Xvoid
- XRunPager(pp, sp)
- X char * pp ;
- X set_type * sp ;
- X{
- X char * cmd ;
- X int i ;
- X id_type * idep ;
- X
- X cmd = (char *)TEMP_ALLOC(SetListSize(sp) + strlen(pp) + 2);
- X strcpy(cmd, pp) ;
- X for (i = 0; i < NextFileNum; ++i) {
- X if (FileList[i]->mask_word < sp->set_size) {
- X if (sp->set_data[FileList[i]->mask_word] & FileList[i]->mask_bit) {
- X strcat(cmd, " ") ;
- X strcat(cmd, FileList[i]->name) ;
- X }
- X }
- X }
- X system(cmd) ;
- X TEMP_FREE(cmd) ;
- X}
- X
- X/* AddSet - add a new set to the universal list of sets. Assign
- X * it the next set number.
- X */
- Xvoid
- XAddSet(sp)
- X set_type * sp ;
- X{
- X if (NextSetNum >= SetSpace) {
- X SetSpace += 1000 ;
- X if (TheSets != NULL) {
- X TheSets = (set_type **)
- X realloc(TheSets, sizeof(set_type *) * SetSpace) ;
- X } else {
- X TheSets = (set_type **)
- X malloc(sizeof(set_type *) * SetSpace) ;
- X }
- X if (TheSets == NULL) {
- X fatal("No memory for TheSets in AddSet") ;
- X }
- X }
- X sp->set_num = NextSetNum ;
- X TheSets[NextSetNum++] = sp ;
- X}
- X
- X/* RunProg - run a program with arguments from id_list and
- X * accept list of file names back from the program which
- X * are installed in the symbol table and used to construct
- X * a new set.
- X */
- Xset_type *
- XRunProg(pp, idlp)
- X char * pp ;
- X id_list_type * idlp ;
- X{
- X int c ;
- X char * cmd ;
- X char * dp ;
- X char file [ MAXCMD ] ;
- X int i ;
- X id_type * idep ;
- X id_type * next_id ;
- X FILE * prog ;
- X set_type * sp ;
- X
- X cmd = (char *)TEMP_ALLOC(ArgListSize(idlp) + strlen(pp) + 2);
- X FlushFiles() ;
- X strcpy(cmd, pp) ;
- X idep = idlp->id_list ;
- X while (idep != NULL) {
- X strcat(cmd, " ") ;
- X strcat(cmd, idep->id) ;
- X next_id = idep->next_id ;
- X free(idep) ;
- X idep = next_id ;
- X }
- X free(idlp) ;
- X
- X /* run program with popen, reading the output. Assume each
- X * white space terminated string is a file name.
- X */
- X prog = popen(cmd, "r") ;
- X dp = file ;
- X while ((c = getc(prog)) != EOF) {
- X if (isspace(c)) {
- X if (dp != file) {
- X *dp++ = '\0' ;
- X InstallFile(file) ;
- X dp = file ;
- X }
- X } else {
- X *dp++ = c ;
- X }
- X }
- X if (dp != file) {
- X *dp++ = '\0' ;
- X InstallFile(file) ;
- X }
- X if (pclose(prog) != 0) {
- X /* if there was an error make an empty set, who knows what
- X * garbage the program printed.
- X */
- X FlushFiles() ;
- X }
- X
- X sp = (set_type *)
- X malloc(sizeof(set_type) + sizeof(unsigned long) * MaxCurFile) ;
- X if (sp == NULL) {
- X fatal("No memory for set in RunProg") ;
- X }
- X sp->set_tail = 0 ;
- X sp->set_desc = (char *)malloc(strlen(cmd) + 1) ;
- X if (sp->set_desc == NULL) {
- X fatal("No memory for set description in RunProg") ;
- X }
- X strcpy(sp->set_desc, cmd) ;
- X sp->set_size = MaxCurFile + 1 ;
- X for (i = 0; i <= MaxCurFile; ++i) {
- X sp->set_data[i] = TheFiles[i] ;
- X }
- X AddSet(sp) ;
- X TEMP_FREE(cmd);
- X return(sp) ;
- X}
- X
- X/* SetDirectory - change the working directory. This will
- X * determine which ID file is found by the subprograms.
- X */
- Xvoid
- XSetDirectory(dir)
- X id_type * dir ;
- X{
- X if (chdir(dir->id) != 0) {
- X fprintf(stderr,"Directory %s not accessible.\n",dir) ;
- X }
- X free(dir) ;
- X}
- X
- X/* SetIntersect - construct a new set from the intersection
- X * of two others. Also construct a new description string.
- X */
- Xset_type *
- XSetIntersect(sp1, sp2)
- X set_type * sp1 ;
- X set_type * sp2 ;
- X{
- X char * desc ;
- X int i ;
- X int len1 ;
- X int len2 ;
- X set_type * new_set ;
- X int new_size ;
- X
- X if (sp1->set_tail || sp2->set_tail) {
- X new_size = MAX(sp1->set_size, sp2->set_size) ;
- X } else {
- X new_size = MIN(sp1->set_size, sp2->set_size) ;
- X }
- X new_set = (set_type *)malloc(sizeof(set_type) +
- X (new_size - 1) * sizeof(unsigned long)) ;
- X if (new_set == NULL) {
- X fatal("No memory for set in SetIntersect") ;
- X }
- X len1 = strlen(sp1->set_desc) ;
- X len2 = strlen(sp2->set_desc) ;
- X desc = (char *)malloc(len1 + len2 + 10) ;
- X if (desc == NULL) {
- X fatal("No memory for set description in SetIntersect") ;
- X }
- X new_set->set_desc = desc ;
- X strcpy(desc,"(") ;
- X ++desc ;
- X strcpy(desc, sp1->set_desc) ;
- X desc += len1 ;
- X strcpy(desc, ") AND (") ;
- X desc += 7 ;
- X strcpy(desc, sp2->set_desc) ;
- X desc += len2 ;
- X strcpy(desc, ")") ;
- X AddSet(new_set) ;
- X new_set->set_size = new_size ;
- X for (i = 0; i < new_size; ++i) {
- X new_set->set_data[i] =
- X ((i < sp1->set_size) ? sp1->set_data[i] : sp1->set_tail) &
- X ((i < sp2->set_size) ? sp2->set_data[i] : sp2->set_tail) ;
- X }
- X new_set->set_tail = sp1->set_tail & sp2->set_tail ;
- X return(new_set) ;
- X}
- X
- X/* SetUnion - construct a new set from the union of two others.
- X * Also construct a new description string.
- X */
- Xset_type *
- XSetUnion(sp1, sp2)
- X set_type * sp1 ;
- X set_type * sp2 ;
- X{
- X char * desc ;
- X int i ;
- X int len1 ;
- X int len2 ;
- X set_type * new_set ;
- X int new_size ;
- X
- X new_size = MAX(sp1->set_size, sp2->set_size) ;
- X new_set = (set_type *)malloc(sizeof(set_type) +
- X (new_size - 1) * sizeof(unsigned long)) ;
- X if (new_set == NULL) {
- X fatal("No memory for set in SetUnion") ;
- X }
- X len1 = strlen(sp1->set_desc) ;
- X len2 = strlen(sp2->set_desc) ;
- X desc = (char *)malloc(len1 + len2 + 9) ;
- X if (desc == NULL) {
- X fatal("No memory for set description in SetUnion") ;
- X }
- X new_set->set_desc = desc ;
- X strcpy(desc,"(") ;
- X ++desc ;
- X strcpy(desc, sp1->set_desc) ;
- X desc += len1 ;
- X strcpy(desc, ") OR (") ;
- X desc += 6 ;
- X strcpy(desc, sp2->set_desc) ;
- X desc += len2 ;
- X strcpy(desc, ")") ;
- X AddSet(new_set) ;
- X new_set->set_size = new_size ;
- X for (i = 0; i < new_size; ++i) {
- X new_set->set_data[i] =
- X ((i < sp1->set_size) ? (sp1->set_data[i]) : sp1->set_tail) |
- X ((i < sp2->set_size) ? (sp2->set_data[i]) : sp2->set_tail) ;
- X }
- X new_set->set_tail = sp1->set_tail | sp2->set_tail ;
- X return(new_set) ;
- X}
- X
- X/* SetInverse - construct a new set from the inverse of another.
- X * Also construct a new description string.
- X *
- X * This is kind of tricky. An inverse set in iid may grow during
- X * the course of a session. By NOTing the set_tail extension the
- X * inverse at any given time will be defined as the inverse against
- X * a universe that grows as additional queries are made and new files
- X * are added to the database.
- X *
- X * Several alternative definitions were possible (snapshot the
- X * universe at the time of the NOT, go read the ID file to
- X * determine the complete universe), but this one was the one
- X * I picked.
- X */
- Xset_type *
- XSetInverse(sp)
- X set_type * sp ;
- X{
- X char * desc ;
- X int i ;
- X set_type * new_set ;
- X
- X new_set = (set_type *)malloc(sizeof(set_type) +
- X (sp->set_size - 1) * sizeof(unsigned long)) ;
- X if (new_set == NULL) {
- X fatal("No memory for set in SetInverse") ;
- X }
- X desc = (char *)malloc(strlen(sp->set_desc) + 5) ;
- X if (desc == NULL) {
- X fatal("No memory for set description in SetInverse") ;
- X }
- X new_set->set_desc = desc ;
- X strcpy(desc,"NOT ") ;
- X desc += 4 ;
- X strcpy(desc, sp->set_desc) ;
- X AddSet(new_set) ;
- X new_set->set_size = sp->set_size ;
- X for (i = 0; i < sp->set_size; ++i) {
- X new_set->set_data[i] = ~ sp->set_data[i] ;
- X }
- X new_set->set_tail = ~ sp->set_tail ;
- X return(new_set) ;
- X}
- X
- X/* RunShell - run a program with arguments from id_list.
- X */
- Xvoid
- XRunShell(pp, idlp)
- X char * pp ;
- X id_list_type * idlp ;
- X{
- X char * cmd ;
- X id_type * idep ;
- X id_type * next_id ;
- X
- X cmd = (char *)TEMP_ALLOC(ArgListSize(idlp) + strlen(pp) + 2);
- X strcpy(cmd, pp) ;
- X idep = idlp->id_list ;
- X while (idep != NULL) {
- X strcat(cmd, " ") ;
- X strcat(cmd, idep->id) ;
- X next_id = idep->next_id ;
- X free(idep) ;
- X idep = next_id ;
- X }
- X free(idlp) ;
- X system(cmd) ;
- X TEMP_FREE(cmd);
- X}
- END_OF_FILE
- if test 17113 -ne `wc -c <'iidfun.c'`; then
- echo shar: \"'iidfun.c'\" unpacked with wrong size!
- fi
- # end of 'iidfun.c'
- fi
- if test -f 'mkid.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mkid.c'\"
- else
- echo shar: Extracting \"'mkid.c'\" \(18633 characters\)
- sed "s/^X//" >'mkid.c' <<'END_OF_FILE'
- Xstatic char copyright[] = "@(#)Copyright (c) 1986, Greg McGary";
- Xstatic char sccsid[] = "@(#)mkid.c 1.4 86/11/06";
- X
- X#include <bool.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <stdio.h>
- X#include <string.h>
- X#include <ctype.h>
- X#include <id.h>
- X#include <bitops.h>
- X#include <errno.h>
- X#include <extern.h>
- X#include "patchlevel.h"
- X
- Xint idnHashCmp();
- Xint idnQsortCmp();
- Xint round2();
- Xstruct idname *newIdName();
- Xvoid extractId();
- Xvoid fileIdArgs();
- Xvoid initHashTable();
- Xvoid oldIdArgs();
- Xvoid rehash();
- Xvoid updateID();
- Xvoid writeID();
- X
- Xlong NameCount; /* Count of names in database */
- Xlong NumberCount; /* Count of numbers in database */
- Xlong StringCount; /* Count of strings in database */
- Xlong SoloCount; /* Count of identifiers that occur only once */
- X
- Xlong HashSize; /* Total Slots in hash table */
- Xlong HashMaxLoad; /* Maximum loading of hash table */
- Xlong HashFill; /* Number of keys inserted in table */
- Xlong HashProbes; /* Total number of probes */
- Xlong HashSearches; /* Total number of searches */
- Xstruct idname **HashTable; /* Vector of idname pointers */
- X
- Xbool Verbose = FALSE;
- X
- Xint ArgsCount = 0; /* Count of args to save */
- Xint ScanCount = 0; /* Count of files to scan */
- Xint PathCount = 0; /* Count of files covered in database */
- Xint BitArraySize; /* Size of bit array slice (per name) */
- X
- Xchar PWDname[BUFSIZ]; /* The current working directory */
- Xchar absID[BUFSIZ]; /* The absolute name of the database */
- X
- X
- Xchar *MyName;
- Xstatic void
- Xusage()
- X{
- X fprintf(stderr, "Usage: %s [-f<idfile>] [-s<dir>] [-r<dir>] [(+|-)l[<lang>]] [-v] [(+|-)S<scanarg>] [-a<argfile>] [-] [-u] [files...]\n", MyName);
- X exit(1);
- X}
- Xmain(argc, argv)
- X int argc;
- X char **argv;
- X{
- X char *arg;
- X int op;
- X FILE *argFILE = NULL;
- X char *idFile = IDFILE;
- X char *rcsDir = NULL;
- X char *sccsDir = NULL;
- X struct idarg *idArgs, *idArgHead;
- X bool keepLang = FALSE;
- X int argsFrom = 0;
- X#define AF_CMDLINE 0x1 /* file args came on command line */
- X#define AF_FILE 0x2 /* file args came from a file (-f<file>) */
- X#define AF_IDFILE 0x4 /* file args came from an old ID file (-u) */
- X#define AF_QUERY 0x8 /* no file args necessary: usage query */
- X
- X MyName = basename(GETARG(argc, argv));
- X if (kshgetwd(PWDname) == NULL) {
- X fprintf(stderr,"%s: cannot get current working directory name.\n",MyName);
- X exit(1);
- X }
- X strcat(PWDname, "/");
- X#ifdef ERRLINEBUF
- X setlinebuf(stderr);
- X#endif
- X
- X idArgs = idArgHead = NEW(struct idarg);
- X
- X /*
- X Process some arguments, and snarf-up some
- X others for processing later.
- X */
- X while (argc) {
- X arg = GETARG(argc, argv);
- X if (*arg != '-' && *arg != '+') {
- X argsFrom |= AF_CMDLINE;
- X idArgs->ida_arg = arg;
- X idArgs->ida_flags = IDA_SCAN|IDA_PATH;
- X idArgs->ida_index = postIncr(&PathCount);
- X ScanCount++;
- X idArgs = (idArgs->ida_next = NEW(struct idarg));
- X continue;
- X }
- X op = *arg++;
- X switch (*arg++)
- X {
- X case 'u':
- X argsFrom |= AF_IDFILE;
- X oldIdArgs(idFile, &idArgs);
- X break;
- X case '\0':
- X argsFrom |= AF_FILE;
- X fileIdArgs(stdin, &idArgs);
- X break;
- X case 'a':
- X if ((argFILE = fopen(arg, "r")) == NULL) {
- X filerr("open", arg);
- X exit(1);
- X }
- X argsFrom |= AF_FILE;
- X fileIdArgs(argFILE, &idArgs);
- X break;
- X case 'f':
- X idFile = arg;
- X break;
- X case 'v':
- X Verbose = TRUE;
- X break;
- X case 'S':
- X if (strchr(&arg[-2], '?')) {
- X setScanArgs(op, arg);
- X argsFrom |= AF_QUERY;
- X }
- X /*FALLTHROUGH*/
- X case 'l':
- X case 's':
- X case 'r':
- X idArgs->ida_arg = &arg[-2];
- X idArgs->ida_index = -1;
- X idArgs->ida_flags = IDA_ARG;
- X idArgs = (idArgs->ida_next = NEW(struct idarg));
- X ArgsCount++;
- X break;
- X default:
- X usage();
- X }
- X }
- X
- X if (argsFrom & AF_QUERY)
- X exit(0);
- X /*
- X File args should only come from one place. Ding the
- X user if arguments came from multiple places, or if none
- X were supplied at all.
- X */
- X switch (argsFrom)
- X {
- X case AF_CMDLINE:
- X case AF_FILE:
- X case AF_IDFILE:
- X if (PathCount > 0)
- X break;
- X /*FALLTHROUGH*/
- X case 0:
- X fprintf(stderr, "%s: Use -u, -f<file>, or cmd-line for file args!\n", MyName);
- X usage();
- X default:
- X fprintf(stderr, "%s: Use only one of: -u, -f<file>, or cmd-line for file args!\n", MyName);
- X usage();
- X }
- X
- X if (ScanCount == 0)
- X exit(0);
- X
- X BitArraySize = (PathCount + 7) >> 3;
- X initHashTable(ScanCount);
- X
- X strcpy(absID, spanPath(PWDname, idFile));
- X if (access(idFile, 06) < 0
- X && (errno != ENOENT || access(dirname(idFile), 06) < 0)) {
- X filerr("modify", idFile);
- X exit(1);
- X }
- X
- X for (idArgs = idArgHead; idArgs->ida_next; idArgs = idArgs->ida_next) {
- X char *(*scanner)();
- X FILE *srcFILE;
- X char *arg, *lang, *suff, *filter;
- X
- X lang = NULL;
- X arg = idArgs->ida_arg;
- X if (idArgs->ida_flags & IDA_ARG) {
- X op = *arg++;
- X switch (*arg++)
- X {
- X case 'l':
- X if (*arg == '\0') {
- X keepLang = FALSE;
- X lang = NULL;
- X break;
- X }
- X if (op == '+')
- X keepLang = TRUE;
- X lang = arg;
- X break;
- X case 's':
- X sccsDir = arg;
- X break;
- X case 'r':
- X rcsDir = arg;
- X break;
- X case 'S':
- X setScanArgs(op, strsav(arg));
- X break;
- X default:
- X usage();
- X }
- X continue;
- X }
- X if (!(idArgs->ida_flags & IDA_SCAN))
- X goto skip;
- X if (lang == NULL) {
- X if ((suff = strrchr(arg, '.')) == NULL)
- X suff = "";
- X if (((lang = getLanguage(suff)) == NULL) &&
- X ((lang = getLanguage(".default")) == NULL)) {
- X fprintf(stderr, "%s: No language assigned to suffix: `%s'\n", MyName, suff);
- X goto skip;
- X }
- X }
- X if ((scanner = getScanner(lang)) == NULL) {
- X fprintf(stderr, "%s: No scanner for language: `%s'\n", MyName, lang);
- X goto skip;
- X }
- X filter = getFilter(suff);
- X if ((srcFILE = openSrcFILE(arg, sccsDir, rcsDir, filter)) == NULL)
- X goto skip;
- X if (Verbose)
- X if (filter) {
- X fprintf(stderr, "%s: ",lang);
- X fprintf(stderr, filter, arg);
- X fprintf(stderr, "\n");
- X } else {
- X fprintf(stderr, "%s: %s\n", lang, arg);
- X }
- X extractId(scanner, srcFILE, idArgs->ida_index);
- X closeSrcFILE(srcFILE, filter);
- X skip:
- X if (!keepLang)
- X lang = NULL;
- X }
- X
- X if (HashFill == 0)
- X exit(0);
- X
- X if (Verbose) {
- X fprintf(stderr, "mkid patchlevel %d:\n", PATCHLEVEL);
- X fprintf(stderr, "Compressing Hash Table...\n");
- X }
- X hashCompress(HashTable, HashSize);
- X if (Verbose)
- X fprintf(stderr, "Sorting Hash Table...\n");
- X qsort(HashTable, HashFill, sizeof(struct idname *), idnQsortCmp);
- X
- X if (argsFrom == AF_IDFILE) {
- X if (Verbose)
- X fprintf(stderr, "Merging Tables...\n");
- X updateID(idFile, idArgHead);
- X }
- X
- X if (Verbose)
- X fprintf(stderr, "Writing `%s'...\n", idFile);
- X writeID(idFile, idArgHead);
- X
- X if (Verbose) {
- X float loadFactor = (float)HashFill / (float)HashSize;
- X float aveProbes = (float)HashProbes / (float)HashSearches;
- X float aveOccur = (float)HashSearches / (float)HashFill;
- X fprintf(stderr, "Names: %ld, ", NameCount);
- X fprintf(stderr, "Numbers: %ld, ", NumberCount);
- X fprintf(stderr, "Strings: %ld, ", StringCount);
- X fprintf(stderr, "Solo: %ld, ", SoloCount);
- X fprintf(stderr, "Total: %ld\n", HashFill);
- X fprintf(stderr, "Occurances: %.2f, ", aveOccur);
- X fprintf(stderr, "Load: %.2f, ", loadFactor);
- X fprintf(stderr, "Probes: %.2f\n", aveProbes);
- X }
- X exit(0);
- X}
- X
- Xvoid
- XextractId(getId, srcFILE, index)
- X register char *(*getId)();
- X register FILE *srcFILE;
- X int index;
- X{
- X register struct idname **slot;
- X register char *key;
- X int flags;
- X
- X while ((key = (*getId)(srcFILE, &flags)) != NULL) {
- X slot = (struct idname **)hashSearch(key, HashTable, HashSize, sizeof(struct idname *), h1str, h2str, idnHashCmp, &HashProbes);
- X HashSearches++;
- X if (*slot != NULL) {
- X (*slot)->idn_flags |= flags;
- X BITSET((*slot)->idn_bitv, index);
- X continue;
- X }
- X *slot = newIdName(key);
- X (*slot)->idn_flags = IDN_SOLO|flags;
- X BITSET((*slot)->idn_bitv, index);
- X if (HashFill++ >= HashMaxLoad)
- X rehash();
- X }
- X}
- X
- X/* As the database is written, may need to adjust the file names.
- X * If we are generating the ID file in a remote directory, then
- X * adjust the file names to be relative to the location of the
- X * ID database.
- X *
- X * (This would be a common useage if you want to make a database
- X * for a directory which you have no write access to, so you cannot
- X * create the ID file.)
- X */
- Xvoid
- XwriteID(idFile, idArgs)
- X char *idFile;
- X struct idarg *idArgs;
- X{
- X register struct idname **idnp;
- X register struct idname *idn;
- X register int i;
- X char *vecBuf;
- X FILE *idFILE;
- X int count;
- X int lasti;
- X long before, after;
- X int length, longest;
- X struct idhead idh;
- X int fixnames;
- X char * lsl;
- X
- X if ((lsl = strrchr(relPath(PWDname, absID),'/')) == NULL) {
- X /* The database is in the cwd, don't adjust the names */
- X fixnames = FALSE;
- X } else {
- X /* The database is not in cwd, adjust names so they are
- X * relative to the location of the database, make absID
- X * just be the directory path to ID.
- X */
- X fixnames = TRUE;
- X *(lsl+1) = '\0';
- X }
- X if ((idFILE = fopen(idFile, "w+")) == NULL) {
- X filerr("create", idFile);
- X exit(1);
- X }
- X fseek(idFILE, (long)sizeof(struct idhead), 0);
- X
- X /* write out the list of pathnames */
- X idh.idh_argo = ftell(idFILE);
- X for (i = lasti = 0; idArgs->ida_next; idArgs = idArgs->ida_next) {
- X if (idArgs->ida_index > 0)
- X while (++lasti < idArgs->ida_index)
- X i++, putc('\0', idFILE);
- X if (fixnames) {
- X fputs(relPath(absID,spanPath(PWDname,idArgs->ida_arg)), idFILE);
- X } else {
- X fputs(idArgs->ida_arg, idFILE);
- X }
- X i++, putc('\0', idFILE);
- X }
- X idh.idh_argc = i;
- X idh.idh_pthc = PathCount;
- X
- X /* write out the list of identifiers */
- X i = 1;
- X if (idh.idh_pthc >= 0x000000ff)
- X i++;
- X if (idh.idh_pthc >= 0x0000ffff)
- X i++;
- X if (idh.idh_pthc >= 0x00ffffff)
- X i++;
- X idh.idh_vecc = i;
- X
- X vecBuf = malloc((idh.idh_pthc + 1) * idh.idh_vecc);
- X
- X putc('\377', idFILE);
- X before = idh.idh_namo = ftell(idFILE);
- X longest = 0;
- X for (idnp = HashTable, i = 0; i < HashFill; i++, idnp++) {
- X idn = *idnp;
- X if ((idn == NULL) || (idn->idn_name[0] == '\0')) {
- X HashFill--; i--;
- X continue;
- X }
- X if (idn->idn_flags & IDN_SOLO)
- X SoloCount++;
- X if (idn->idn_flags & IDN_NUMBER)
- X NumberCount++;
- X if (idn->idn_flags & IDN_NAME)
- X NameCount++;
- X if (idn->idn_flags & IDN_STRING)
- X StringCount++;
- X
- X putc((*idnp)->idn_flags, idFILE);
- X fputs(idn->idn_name, idFILE);
- X putc('\0', idFILE);
- X
- X count = bitsToVec(vecBuf, (*idnp)->idn_bitv, idh.idh_pthc, idh.idh_vecc);
- X fwrite(vecBuf, idh.idh_vecc, count, idFILE);
- X putc('\377', idFILE);
- X after = ftell(idFILE);
- X
- X if ((length = (after - before)) > longest)
- X longest = length;
- X before = after;
- X }
- X idh.idh_namc = i;
- X putc('\377', idFILE);
- X idh.idh_endo = ftell(idFILE);
- X idh.idh_bsiz = longest;
- X
- X /* write out the header */
- X strncpy(idh.idh_magic, IDH_MAGIC, sizeof(idh.idh_magic));
- X idh.idh_vers = IDH_VERS;
- X fseek(idFILE, 0L, 0);
- X fwrite(&idh, sizeof(struct idhead), 1, idFILE);
- X
- X fclose(idFILE);
- X}
- X
- X/*
- X Build an idarg vector from pathnames contained in an existing
- X id file. Only include pathnames for files whose modification
- X time is later than that of the id file itself.
- X*/
- Xvoid
- XoldIdArgs(idFile, idArgsP)
- X char *idFile;
- X struct idarg **idArgsP;
- X{
- X struct stat statBuf;
- X struct idhead idh;
- X FILE *idFILE;
- X register int i;
- X register char *strings;
- X time_t idModTime;
- X
- X if ((idFILE = fopen(idFile, "r")) == NULL) {
- X filerr("open", idFile);
- X usage();
- X }
- X /*
- X * Open the id file, get its mod-time, and read its header.
- X */
- X if (fstat(fileno(idFILE), &statBuf) < 0) {
- X filerr("stat", idFile);
- X usage();
- X }
- X idModTime = statBuf.st_mtime;
- X fread(&idh, sizeof(struct idhead), 1, idFILE);
- X if (!strnequ(idh.idh_magic, IDH_MAGIC, sizeof(idh.idh_magic))) {
- X fprintf(stderr, "%s: Not an id file: `%s'\n", MyName, idFile);
- X exit(1);
- X }
- X if (idh.idh_vers != IDH_VERS) {
- X fprintf(stderr, "%s: ID version mismatch (%ld,%ld)\n", MyName, idh.idh_vers, IDH_VERS);
- X exit(1);
- X }
- X
- X /*
- X * Read in the id pathnames, compare their mod-times with
- X * the id file, and incorporate the pathnames of recently modified
- X * files in the idarg vector. Also, construct a mask of
- X * bit array positions we want to turn off when we build the
- X * initial hash-table.
- X */
- X fseek(idFILE, idh.idh_argo, 0);
- X strings = malloc(i = idh.idh_namo - idh.idh_argo);
- X fread(strings, i, 1, idFILE);
- X ScanCount = 0;
- X for (i = 0; i < idh.idh_argc; i++) {
- X (*idArgsP)->ida_arg = strings;
- X if (*strings == '+' || *strings == '-') {
- X (*idArgsP)->ida_flags = IDA_ARG;
- X (*idArgsP)->ida_index = -1;
- X } else {
- X (*idArgsP)->ida_flags = IDA_PATH;
- X (*idArgsP)->ida_index = postIncr(&PathCount);
- X if (stat(strings, &statBuf) < 0) {
- X filerr("stat", strings);
- X } else if (statBuf.st_mtime >= idModTime) {
- X (*idArgsP)->ida_flags |= IDA_SCAN;
- X ScanCount++;
- X }
- X }
- X (*idArgsP) = ((*idArgsP)->ida_next = NEW(struct idarg));
- X while (*strings++)
- X ;
- X }
- X if (ScanCount == 0) {
- X fclose(idFILE);
- X exit(0);
- X }
- X fclose(idFILE);
- X}
- X
- Xvoid
- XupdateID(idFile, idArgs)
- X char *idFile;
- X struct idarg *idArgs;
- X{
- X struct idname *idn;
- X struct idhead idh;
- X register char *bitArray;
- X char *entry;
- X register int i;
- X FILE *idFILE;
- X int cmp, count, size;
- X char *bitsOff;
- X struct idname **newTable, **mergeTable;
- X struct idname **t1, **t2, **tm;
- X
- X if ((idFILE = fopen(idFile, "r")) == NULL)
- X filerr("open", idFile);
- X fread(&idh, sizeof(struct idhead), 1, idFILE);
- X
- X entry = malloc(idh.idh_bsiz);
- X
- X bitsOff = malloc(BitArraySize);
- X bzero(bitsOff, BitArraySize);
- X for (i = 0; idArgs->ida_next; idArgs = idArgs->ida_next)
- X if (idArgs->ida_flags & IDA_SCAN)
- X BITSET(bitsOff, idArgs->ida_index);
- X
- X bitArray = malloc(BitArraySize);
- X bzero(bitArray, BitArraySize);
- X t2 = newTable = (struct idname **)malloc((idh.idh_namc + 1) * sizeof(struct idname *));
- X fseek(idFILE, idh.idh_namo, 0);
- X count = 0;
- X for (i = 0; i < idh.idh_namc; i++) {
- X size = 1 + fgets0(entry, idh.idh_bsiz, idFILE);
- X getsFF(&entry[size], idFILE);
- X vecToBits(bitArray, &entry[size], idh.idh_vecc);
- X bitsclr(bitArray, bitsOff, BitArraySize);
- X if (!bitsany(bitArray, BitArraySize))
- X continue;
- X *t2 = newIdName(ID_STRING(entry));
- X bitsset((*t2)->idn_bitv, bitArray, BitArraySize);
- X (*t2)->idn_flags = ID_FLAGS(entry);
- X bzero(bitArray, BitArraySize);
- X t2++; count++;
- X }
- X *t2 = NULL;
- X
- X t1 = HashTable;
- X t2 = newTable;
- X tm = mergeTable = (struct idname **)calloc(HashFill + count + 1, sizeof(struct idname *));
- X while (*t1 && *t2) {
- X cmp = strcmp((*t1)->idn_name, (*t2)->idn_name);
- X if (cmp < 0)
- X *tm++ = *t1++;
- X else if (cmp > 0)
- X *tm++ = *t2++;
- X else {
- X (*t1)->idn_flags |= (*t2)->idn_flags;
- X (*t1)->idn_flags &= ~IDN_SOLO;
- X bitsset((*t1)->idn_bitv, (*t2)->idn_bitv, BitArraySize);
- X *tm++ = *t1;
- X t1++, t2++;
- X }
- X }
- X while (*t1)
- X *tm++ = *t1++;
- X while (*t2)
- X *tm++ = *t2++;
- X *tm = NULL;
- X HashTable = mergeTable;
- X HashFill = tm - mergeTable;
- X}
- X
- X/*
- X Cons up a list of idArgs as supplied in a file.
- X*/
- Xvoid
- XfileIdArgs(argFILE, idArgsP)
- X FILE *argFILE;
- X struct idarg **idArgsP;
- X{
- X int fileCount;
- X char buf[BUFSIZ];
- X char *arg;
- X
- X fileCount = 0;
- X while (fgets(buf, sizeof(buf), argFILE)) {
- X (*idArgsP)->ida_arg = arg = strnsav(buf, strlen(buf)-1);
- X if (*arg == '+' || *arg == '-') {
- X (*idArgsP)->ida_flags = IDA_ARG;
- X (*idArgsP)->ida_index = -1;
- X } else {
- X (*idArgsP)->ida_flags = IDA_SCAN|IDA_PATH;
- X (*idArgsP)->ida_index = postIncr(&PathCount);
- X ScanCount++;
- X }
- X (*idArgsP) = ((*idArgsP)->ida_next = NEW(struct idarg));
- X }
- X}
- X
- Xvoid
- XinitHashTable(pathCount)
- X int pathCount;
- X{
- X if ((HashSize = round2((pathCount << 6) + 511)) > 0x8000)
- X HashSize = 0x8000;
- X HashMaxLoad = HashSize - (HashSize >> 4); /* about 94% */
- X HashTable = (struct idname **)calloc(HashSize, sizeof(struct idname *));
- X}
- X
- X/*
- X Double the size of the hash table in the
- X event of overflow...
- X*/
- Xvoid
- Xrehash()
- X{
- X long oldHashSize = HashSize;
- X struct idname **oldHashTable = HashTable;
- X register struct idname **htp;
- X register struct idname **slot;
- X
- X HashSize *= 2;
- X if (Verbose)
- X fprintf(stderr, "Rehashing... (doubling size to %ld)\n", HashSize);
- X HashMaxLoad = HashSize - (HashSize >> 4);
- X HashTable = (struct idname **)calloc(HashSize, sizeof(struct idname *));
- X
- X HashFill = 0;
- X for (htp = oldHashTable; htp < &oldHashTable[oldHashSize]; htp++) {
- X if (*htp == NULL)
- X continue;
- X slot = (struct idname **)hashSearch((*htp)->idn_name, (char *)HashTable, HashSize, sizeof(struct idname *), h1str, h2str, idnHashCmp, &HashProbes);
- X if (*slot) {
- X fprintf(stderr, "%s: Duplicate hash entry!\n");
- X exit(1);
- X }
- X *slot = *htp;
- X HashSearches++;
- X HashFill++;
- X }
- X free(oldHashTable);
- X}
- X
- X/*
- X Round a given number up to the nearest power of 2.
- X*/
- Xint
- Xround2(rough)
- X int rough;
- X{
- X int round;
- X
- X round = 1;
- X while (rough) {
- X round <<= 1;
- X rough >>= 1;
- X }
- X return round;
- X}
- X
- X/*
- X `compar' function for hashSearch()
- X*/
- Xint
- XidnHashCmp(key, idn)
- X char *key;
- X struct idname **idn;
- X{
- X int collate;
- X
- X if (*idn == NULL)
- X return 0;
- X
- X if ((collate = strcmp(key, (*idn)->idn_name)) == 0)
- X (*idn)->idn_flags &= ~IDN_SOLO; /* we found another occurance */
- X
- X return collate;
- X}
- X
- X/*
- X `compar' function for qsort().
- X*/
- Xint
- XidnQsortCmp(idn1, idn2)
- X struct idname **idn1;
- X struct idname **idn2;
- X{
- X if (*idn1 == *idn2)
- X return 0;
- X if (*idn1 == NULL)
- X return 1;
- X if (*idn2 == NULL)
- X return -1;
- X
- X return strcmp((*idn1)->idn_name, (*idn2)->idn_name);
- X}
- X
- X/*
- X Allocate a new idname struct and fill in the name field.
- X We allocate memory in large chunks to avoid frequent
- X calls to malloc() which is a major pig.
- X*/
- Xstruct idname *
- XnewIdName(name)
- X char *name;
- X{
- X register struct idname *idn;
- X register char *allocp;
- X register int allocsiz;
- X static char *allocBuf = NULL;
- X static char *allocEnd = NULL;
- X#define ALLOCSIZ (8*1024)
- X
- X allocsiz = sizeof(struct idname) + strlen(name) + 1 + BitArraySize;
- X allocsiz += (sizeof(long) - 1);
- X allocsiz &= ~(sizeof(long) - 1);
- X
- X allocp = allocBuf;
- X allocBuf += allocsiz;
- X if (allocBuf > allocEnd) {
- X allocBuf = malloc(ALLOCSIZ);
- X allocEnd = &allocBuf[ALLOCSIZ];
- X allocp = allocBuf;
- X allocBuf += allocsiz;
- X }
- X
- X idn = (struct idname *)allocp;
- X allocp += sizeof(struct idname);
- X idn->idn_bitv = allocp;
- X for (allocsiz = BitArraySize; allocsiz--; allocp++)
- X *allocp = '\0';
- X idn->idn_name = strcpy(allocp, name);
- X
- X return idn;
- X}
- X
- Xint
- XpostIncr(ip)
- X int *ip;
- X{
- X register int i;
- X int save;
- X
- X save = *ip;
- X i = save + 1;
- X if ((i & 0x00ff) == 0x00ff)
- X i++;
- X if ((i & 0xff00) == 0xff00) /* This isn't bloody likely */
- X i += 0x100;
- X *ip = i;
- X
- X return save;
- X}
- X
- X/*
- X Move all non-NULL table entries to the front of the table.
- X return the number of non-NULL elements in the table.
- X*/
- Xint
- XhashCompress(table, size)
- X char **table;
- X int size;
- X{
- X register char **front;
- X register char **back;
- X
- X front = &table[-1];
- X back = &table[size];
- X
- X for (;;) {
- X while (*--back == NULL)
- X ;
- X if (back < front)
- X break;
- X while (*++front != NULL)
- X ;
- X if (back < front)
- X break;
- X *front = *back;
- X }
- X
- X return (back - table + 1);
- X}
- END_OF_FILE
- if test 18633 -ne `wc -c <'mkid.c'`; then
- echo shar: \"'mkid.c'\" unpacked with wrong size!
- fi
- # end of 'mkid.c'
- fi
- echo shar: End of archive 5 \(of 7\).
- cp /dev/null ark5isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 7 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
- exit 0 # Just in case...
-